<?php

/**
 *    支付网关通知接口
 *
 *    @author    censhuixing
 *    @time    2014-08-11
 */
class PaynotifyApp extends MallbaseApp
{


	/**
     *    余额支付完成后返回的URL，在此只进行提示，不对订单进行任何修改操作,这里不严格验证，不改变订单状态
     *    @author    Garbin
     *    @return    void
     */
	function capital()
	{

		$total_price  = floatval($_GET['price']);//订单总额
		$shopcar_step = 'shopcar03';
		$this->assign('shopcar_step', $shopcar_step);
		$this->_curlocal(LANG::get('pay_successed'));
		$this->assign('total_fee', $total_price);
		$this->display('paynotify.index.html');
	}

	/**
     *    支付完成后返回的URL，在此只进行提示，不对订单进行任何修改操作,这里不严格验证，不改变订单状态
     *
     *    @author    Garbin
     *    @return    void
     */
	function index()
	{

		//这里是支付宝，财付通等当订单状态改变时的通知地址
		$contact_url  =  'index.php?app=article&act=view&article_id=30';
		$code   = isset($_GET['code']) ? trim($_GET['code']) : 0; //哪个支付方式
		if (!$code)
		{
			/* 无效的通知请求 */
			$this->show_warning('no_such_payment','联系客服',$contact_url);
			exit;
		}

		/* 调用相应的支付方式 */
		$file = ROOT_PATH."/includes/payments/{$code}.php";
		if(file_exists($file))
		{
			include_once($file);
			$payment = new $code();
		}
		else
		{
			/* 无效的支付方式 */
			$this->show_warning('无效的支付方式','联系客服',$contact_url);
			exit;
		}

		/* 获取验证结果 */
		$result=$payment->respond();

		if ($result == 1)//成功
		{
			$this->save_log($code);//成功，记录日志
			/* 只有支付时会使用到return_url，所以这里显示的信息是支付成功的提示信息 */
			//显示位置
			$shopcar_step = 'shopcar03';
			$this->assign('shopcar_step', $shopcar_step);
			$this->_curlocal(LANG::get('pay_successed'));
			$this->assign('total_fee', $payment->get_total_fee());
			$this->display('paynotify.index.html');

		}
		else //失败
		{

			//显示位置
			$shopcar_step = 'shopcar03';
			$this->assign('shopcar_step', $shopcar_step);
			$error_msg = $payment->error_message($result);
			/*	$msg .='<p><span>'.$error_msg.'</span><br>';
			$msg .='1、如果您已支付，<a href="'.$site_url.'/index.php?app=buyer_order&type=allorder" class="linkbtn" target="_blank">请点此查看订单</a><br>';
			$msg .='2、如果您存在其他疑问，<a href="'.$contact_url.'" class="linkbtn" target="_blank">请联系客服</a></p>';
			$this->show_warning($msg);*/
			$this->assign('error_msg', $error_msg);
			$this->assign('contact_url', $contact_url);

			$this->display('paynotify.error.html');

			exit;

		}

	}

	/**
     *    支付完成后，外部网关的通知地址，在此会进行订单状态的改变，这里严格验证，改变订单状态
     *
     *    @author    censhuixing
     *    @return    void
     */
	function async()
	{

		//这里是支付宝，财付通等当订单状态改变时的通知地址
		$code   = isset($_REQUEST['code']) ? trim($_REQUEST['code']) : 0; //哪个支付方式
		if (!$code)
		{
			/* 无效的通知请求 */
			$arr = $_REQUEST;
			$arr['error_message'] = '无效的通知请求';
			$this->error_log($arr);
			echo 'fail';
			exit;
		}

		$this->save_log($code);//记录回调参数

		/* 调用相应的支付方式 */
		$file = ROOT_PATH."/includes/payments/{$code}.php";
		if(file_exists($file))
		{
			include_once($file);
			$payment = new $code();
		}
		else
		{
			$arr = $_REQUEST;
			$arr['error_message'] = '无效的支付方式';
			$this->error_log($arr);
			$payment->verify_result(false);//按支付接口的文档要求响应失败
			exit;
		}

		/* 获取验证结果 */
		$result=$payment->respond();

		if ($result != 1 )//失败
		{
			/* 支付失败 */
			$error_msg = $payment->error_message($result);//获取支付接口返回的错误信息
			$arr = $_REQUEST;
			$arr['error_message'] = $error_msg;
			$this->error_log($arr);
			$payment->verify_result(false);//按支付接口的文档要求响应失败
			exit;
		}

		/*----------通知验证结束----------*/
		/*----------本地验证开始----------*/
		else
		{

			//按支付方式获取外部交易号
			$trans_code  = $payment->get_out_trade_no();
			//获取订单信息
			//一个外部交易号有可能包含多个订单
			$model_orderpay =& m('orderpay');
			$trade_info  = $model_orderpay->get_out_trade_sn($trans_code);

			if (empty($trade_info))
			{
				$arr = $_REQUEST;
				$arr['error_message'] = '没有该订单';
				$this->error_log($arr);
				$payment->verify_result(false);//按支付接口的文档要求响应失败
				exit;
			}
			//检查金额是否相符
			$online_price = $trade_info['total_price'] - $trade_info['balance_price'];
			$online_price = round($online_price,2);
			
			$ret = $payment->check_total_fee($online_price);
			if ($ret === false)
			{
				$arr = $_REQUEST;
				$arr['error_message'] = '金额不相符';
				$this->error_log($arr);
				$payment->verify_result(false);//按支付接口的文档要求响应失败
				exit;
			}

			//按支付方式取得费率
			$pay_rate    = $payment->get_pay_rate($online_price);//费率
			//$pay_amount  = $online_price*$pay_rate;//手续费

			//如果订单中有使用了余额支付,则将之前下单后冻结的资金消费掉
			if($trade_info['balance_price']>0 && $trade_info['pay_time'] == 0)
			{
				$user_id         = $trade_info['user_id'];
				$model_usermoney =& m('usermoney');
				$frozen_money  = $trade_info['balance_price'] ;//冻结金额

				$sql = "update {$model_usermoney->table} set frozen_money = frozen_money - $frozen_money where user_id = '{$user_id}'";
				$model_usermoney->db->query($sql);

				$accout_log = array(
				'user_id' => $user_id,
				'order_no' => $trans_code,//关联交易号,
				'user_money' => $frozen_money,
				'change_time' => gmtime(),
				'change_desc' => '礼品卡支付订单',
				'change_type' =>2,
				);

				$model_accountlog =& m('accountlog');//添加到账户充值记录
				$model_accountlog->add($accout_log);
			}
			//所有验证通过，更新订单状态
			$order_pay['pay_time'] = time();
			$order_pay['trade_no'] = isset($_REQUEST['trade_no']) ? trim($_REQUEST['trade_no']) : 0; //支付宝流水号;
			$model_orderpay->edit("out_trade_sn={$trans_code}", $order_pay);


			//按外部交易号取得订单信息,一个外部交易号有可能包含多个订单
			$order_info = $model_orderpay->find(array(
			'conditions'    => "out_trade_sn= '".$trans_code."'",
			'fields'        => 'this.order_id,this.payment_code,this.out_trade_sn,this.order_price',
			));

			//print_r($order_info);die();
			$notify_result['target'] = ORDER_ACCEPTED;//更新订单状态为买家已付款，等待卖家发货
			if(is_array($order_info))
			{
				foreach ($order_info as $id => $order)
				{
					//改变订单状态
                                        if($trade_info['balance_price'] >= $order['order_price']){
                                            $notify_result['pay_amount']   = 0;//手续费
                                            $trade_info['balance_price'] = $trade_info['balance_price'] - $order['order_price'];
                                        }else{
                                            $notify_result['pay_amount']   = round(($order['order_price'] - $trade_info['balance_price'])*$pay_rate,2);//手续费
                                            $trade_info['balance_price'] = 0;
                                        }
                                        $notify_result['payment_code'] = $code;//支付类型
                                        $notify_result['payment_rate'] = $pay_rate;//费率
					$notify_result['out_trade_sn'] = $trans_code;//外部交易号
					$this->_change_order_status($order['order_id'], 'normal', $notify_result);
				}

			}

			//给支付网关响应结果
			$payment->verify_result(true);
			die();

			//优化时可以加入消息队列
			/*if ($notify_result['target'] == ORDER_ACCEPTED)
			{

			if(is_array($order_info))
			{
			foreach ($order_info as $id => $order)
			{
			// 发送邮件给卖家，提醒付款成功
			$model_order =& m('order');
			$send_order_info  = $model_order->get($order['order_id']);

			$model_member =& m('member');
			$seller_info  = $model_member->get($send_order_info['seller_id']);

			$mail = get_mail('toseller_online_pay_success_notify', array('order' => $send_order_info));
			$this->_mailto($seller_info['email'], addslashes($mail['subject']), addslashes($mail['message']));

			//同步发送
			$this->_sendmail(false);
			}

			}


			}*/


		}



	}

	/**
     *    改变订单状态
     *
     *    @author    Garbin
     *    @param     int $order_id
     *    @param     string $order_type
     *    @param     array  $notify_result
     *    @return    void
     */
	function _change_order_status($order_id, $order_type, $notify_result)
	{
		/* 将验证结果传递给订单类型处理 */
		$order_type  =& ot($order_type);
		$order_type->respond_notify($order_id, $notify_result);    //响应通知
	}
	/**
     * 参数回调日志
     *
     * @param 支付渠道 $code
     */
	function save_log($code)
	{
		$dir        =   date('Y').'_'.date('m');
		$path_root = ROOT_PATH.'/log/pay_log/'.$dir;//绝对路径
		ecm_mkdir($path_root);
		$filename   =   $path_root.'/'.$code.'_'.date('d').'.log';

		//   首先我们要确定文件存在并且可写。
		//if (is_writable($filename))
		//{
		$querystring = "\n" . http_build_query($_REQUEST);
		//   在这个例子里，我们将使用添加模式打开$filename，
		//   因此，文件指针将会在文件的开头，
		//   那就是当我们使用fwrite()的时候，$somecontent将要写入的地方。
		if   (!$handle   =   fopen($filename,   'a'))
		{
			print   "不能打开文件   $filename ";
			exit;
		}

		//   将$somecontent写入到我们打开的文件中。
		if   (!fwrite($handle,   $querystring))
		{
			print   "不能写入到文件   $filename ";
			exit;
		}

		//print   "成功地将   $somecontent   写入到文件$filename ";
		fwrite($handle,   "\r\n");
		fclose($handle);

		//}
		/*	else
		{
		print   "文件   $filename   不可写 ";
		}*/

	}

	/**
     * 错误日志
     *
     * @param $arr
     */
	function error_log($arr = array())
	{
		if(empty($arr))
		return;

		$arr['time']  = date('Y-m-d H:i:s');//加上时间记录
		$content = "\r";
		$content .= "\$".time()."= " . var_export($arr, true) . ";\r\n";
		$dir =   date('Y-m-d');
		$file = ROOT_PATH.'/log/pay_log/'.$dir.'.log';//绝对路径
		file_put_contents($file,$content,FILE_APPEND);

	}

}

?>
